package com.mspbots.sync.wise.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.sync.BaseGenericService;
import com.mspbots.sync.model.ExceptionLog;
import com.mspbots.sync.utils.WiseParamsUtils;
import com.mspbots.sync.wise.client.ClientProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Iterator;
import java.util.Map;

/**
 * com.mspbots.sync.wise.service.AgreementService
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/11/14
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class CompanyService extends BaseGenericService {

    public Flux<JsonNode> getCompanies(ClientProperties configuration) {
        MultiValueMap<String, String> params = WiseParamsUtils.paginationBuild("1", null);
        return this.cwWebClient.fetch("/company/companies", params)
                .subscriberContext(ctx -> ctx.put("properties", configuration))
                .switchMap(jsonNode -> {
                    if (ObjectUtils.isEmpty(jsonNode.get("id"))) {
                        log.error("This tenant sync COMPANIES error.msg: {}", jsonNode);
                        this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                                .tenantId(configuration.getTenantId()).name("Connect wise")
                                .status(500).type("SYNC-WISE-COMPANIES").msg("Connect wise sync COMPANIES entry error.")
                                .extend(jsonNode).build());
                        return Flux.empty();
                    }
                    return Flux.just(jsonNode);
                });

    }

    public Flux<JsonNode> getCompanyTeamRoles(ClientProperties configuration, Integer companyId) {
        MultiValueMap<String, String> params = WiseParamsUtils.paginationBuild("1", null);
        return this.cwWebClient.fetch("/company/companies/" + companyId + "/teams", params)
                .subscriberContext(ctx -> ctx.put("properties", configuration))
                .switchMap(jsonNode -> {
                    if (ObjectUtils.isEmpty(jsonNode.get("id"))) {
                        log.error("This tenant sync companies team roles error.msg: {}", jsonNode);
                        this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                                .tenantId(configuration.getTenantId()).name("Connect wise")
                                .msg("Connect wise sync Company Team Roles entry error.")
                                .status(500).type("SYNC-COMPANIES-TEAM-ROLES")
                                .extend(jsonNode).build());
                        return Flux.empty();
                    }
                    return Flux.just(jsonNode);
                })
                .onErrorResume(err -> {
                    log.error("This tenant {} sync companies team roles error.msg: {}",
                            configuration.getTenantId(), err.getMessage());
                    this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                            .tenantId(configuration.getTenantId()).name("Connect wise")
                            .status(500).type("SYNC-COMPANIES-TEAM-ROLES")
                            .msg(err.getMessage()).build());
                    return Flux.empty();
                });
    }

    public Mono<Object> getAgreements(Map<String, String> params) {
        Integer tenantId = Integer.parseInt(params.get("tenantId"));
        return this.onGetWiseProperties(tenantId)
                .flatMap(configuration -> this.getAgreements(configuration).collectList());
    }

    public Flux<JsonNode> getAgreements(ClientProperties configuration) {
        MultiValueMap<String, String> params = WiseParamsUtils.paginationBuild("1", null);
        return this.cwWebClient.fetch("/finance/agreements", params)
                .subscriberContext(ctx -> ctx.put("properties", configuration))
                .switchMap(jsonNode -> {
                    if (ObjectUtils.isEmpty(jsonNode.get("id"))) {
                        log.error("This tenant sync AGREEMENTS error.msg: {}", jsonNode);
                        this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                                .tenantId(configuration.getTenantId()).name("Connect wise")
                                .status(500).type("SYNC-WISE-AGREEMENTS").msg("Connect wise sync AGREEMENTS entry error.")
                                .extend(jsonNode).build());
                        return Flux.empty();
                    }
                    return Flux.just(jsonNode);
                })
                .flatMap(jsonNode -> this.getAdditions(configuration, jsonNode.get("id").asInt())
                        .map(acds -> {
                            ObjectNode objectNode = jsonNode.deepCopy();
                            Iterator<JsonNode> elements = acds.elements();
                            double billAmount = objectNode.get("billAmount").asDouble(0);
                            while (elements.hasNext()) {
                                JsonNode adts = elements.next();
                                log.debug("Connect wise sync ADDITIONS,tenant:{},agreement:{},billAmount:{},extPrice:{}",
                                        configuration.getTenantId(), jsonNode.get("id"),
                                        billAmount, adts.get("extPrice").asDouble(0));
                                billAmount = billAmount + adts.get("extPrice").asDouble(0);
                            }
                            objectNode.put("billAmount", billAmount);
                            objectNode.set("additions", acds);
                            return objectNode;
                        }).defaultIfEmpty(jsonNode.deepCopy()));
    }

    private Mono<JsonNode> getAdditions(ClientProperties configuration, Integer agreementId) {
        MultiValueMap<String, String> queryParams = WiseParamsUtils.paginationBuild("1", null);
        return cwWebClient.getRepository("finance/agreements/" + agreementId + "/additions", queryParams)
                .subscriberContext(ctx -> ctx.put("properties", configuration))
                .onErrorResume(err -> {
                    log.error("This tenant sync ADDITIONS is empty. msg: {}", err.getMessage());
                    this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                            .tenantId(configuration.getTenantId()).name("Connect wise")
                            .status(500).type("SYNC-WISE-ADDITIONS").msg("Connect wise sync additions entry error. msg: " + err.getMessage())
                            .build());
                    return Mono.empty();
                });
    }

    public Flux<JsonNode> getContacts(ClientProperties configuration) {
        return this.cwWebClient.fetch("/company/contacts",
                WiseParamsUtils.paginationBuild("1", null))
                .switchMap(jsonNode -> {
                    if (ObjectUtils.isEmpty(jsonNode.get("id"))) {
                        log.error("This tenant sync CONTACTS error.msg: {}", jsonNode);
                        this.messagingTemplate.convertAndSend("exception.log", ExceptionLog.builder()
                                .tenantId(configuration.getTenantId()).name("Connect wise")
                                .status(500).type("SYNC-WISE-CONTACTS").msg("Connect wise sync CONTACTS entry error.")
                                .extend(jsonNode).build());
                        return Flux.empty();
                    }
                    return Flux.just(jsonNode);
                });
    }


    public Mono<JsonNode> getContacts(Map<String, String> params) {
        Integer tenantId = Integer.parseInt(params.get("tenantId"));
        params.put("orderBy", "id desc");
        params.put("pageSize", "500");
        return this.onGetWiseProperties(tenantId)
                .flatMap(configuration -> cwWebClient.getRepository("/company/contacts/",
                        WiseParamsUtils.mapToMultiValueMapBuild(params))
                        .subscriberContext(ctx -> ctx.put("properties", configuration)));
    }
}
